package net.gdface.facelog;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import gu.dtalk.CmdItem;
import gu.dtalk.ICmdImmediateAdapter;
import gu.dtalk.ItemBuilder;
import gu.dtalk.MenuItem;
import gu.dtalk.OptionType;
import gu.dtalk.RootMenu;
import gu.dtalk.exception.CmdExecutionException;
import gu.simplemq.SimplemqContext;
import net.gdface.facelog.common.DtalkCommonConstants;
import net.gdface.facelog.common.ExtractFeatureReturn;
import net.gdface.facelog.common.FaceApiCmdAdapter;
import net.gdface.image.ImageErrorException;
import net.gdface.sdk.CapacityFieldConstant;
import net.gdface.sdk.CodeInfo;
import net.gdface.sdk.FaceApi;
import net.gdface.sdk.NotFaceDetectedException;
import net.gdface.utils.BinaryUtils;

import static com.google.common.base.Preconditions.checkState;
import static net.gdface.utils.ConditionChecks.checkNotNull;

public class DtalkServiceMenu extends RootMenu implements ServiceConstant,DtalkCommonConstants,CapacityFieldConstant {

	private static final FacelogTypeTransformer TRANS = new FacelogTypeTransformer();
	public DtalkServiceMenu() {
	}
	public DtalkServiceMenu init(){
		MenuItem cmd = 
				ItemBuilder.builder(MenuItem.class)
					.name(MENU_CMD)
					.uiName("基本设备命令")
					.hide()
					.addChilds(
							ItemBuilder.builder(CmdItem.class).name(CMD_FACEAPI).uiName("调用FaceApi接口").hide().addChilds(
									OptionType.STRING.builder().name(CMD_FACEAPI_SDKVERSION).uiName("算法类型").required().instance(),
									OptionType.STRING.builder().name(CMD_FACEAPI_METHOD).uiName("接口方法名").required().instance(),
									OptionType.STRING.builder().name(CMD_FACEAPI_PARAMETERS).uiName("参数列表(JSON array)").required().instance()
									).instance().setImmediateCmdAdapter(FaceApiCmdAdapter.INSTANCE),
							ItemBuilder.builder(CmdItem.class).name(CMD_EXTRACT).uiName("调用人脸识别算法对图像提取特征,返回特征数据及人脸位置信息").hide().addChilds(
									OptionType.IMAGE.builder().name(CMD_EXTRACT_IMAGE).uiName("接口方法名").required().instance()
									).instance().setImmediateCmdAdapter(ExtractFeatureBaseFaceApi.ADAPTER))
					.instance();
		addChilds(cmd);
		return this;
	}
	/**
	 * 基于 FaceApi 实现通用提取人脸特征的任务,返回{@link ExtractFeatureReturn}列表
	 * @author guyadong
	 *
	 */
	static class ExtractFeatureBaseFaceApi implements ICmdImmediateAdapter{
		public static final ExtractFeatureBaseFaceApi ADAPTER = new ExtractFeatureBaseFaceApi();
		private ConcurrentMap<String, FaceApi> faceApiInstances = Maps.newConcurrentMap();
		private ExtractFeatureBaseFaceApi() {
		}
		/**
		 * 如果没有定义FaceApi
		 * @param faceApi
		 */
		public void bindFaceApi(FaceApi faceApi) {
			if(faceApi  != null){
				faceApiInstances.put(faceApi.sdkCapacity().get(C_SDK_VERSION), faceApi);
			}
		}
		
		/**
		 * 从通道名中获取SDK版本号,失败则抛出异常
		 * @return SDK版本号
		 * @throws CmdExecutionException 获取SDK版本号失败
		 */
		private static String parseSdkVersion() throws CmdExecutionException{
			try {
				String channelName = SimplemqContext.context.get().getCurrentChannelName();
				checkState(channelName != null,  "channelName is null");
				return RedisManagement.parseSdkVersion(channelName);				
			} catch (Exception e) {
				throw new CmdExecutionException(e);
			}
		}
		
		@Override
		public List<ExtractFeatureReturn> apply(Map<String, Object> input) throws CmdExecutionException {
			byte[] image = (byte[]) input.get(CMD_EXTRACT_IMAGE);
			String sdkVersion = parseSdkVersion();
			FaceApi faceApi = checkNotNull(faceApiInstances.get(sdkVersion), CmdExecutionException.class, 
					"NOT FOUND FaceApi instance for sdkVersion:%s", sdkVersion);
			try {
				CodeInfo[] codes = faceApi.detectAndGetCodeInfo(image, 0);
				List<ExtractFeatureReturn> extractFeatureReturns = 
						Lists.newArrayList(TRANS.to(codes,CodeInfo.class,ExtractFeatureReturn.class));
				String imageMd5 = BinaryUtils.getMD5String(image);
				for(ExtractFeatureReturn r:extractFeatureReturns){
					r.getFaceBean().setImageMd5(imageMd5);
				}
				return extractFeatureReturns;
			} catch (ImageErrorException | NotFaceDetectedException e) {
				throw new CmdExecutionException(e);
			}
		}		
	}
}
